package org.jground.rx.ui.zk.login;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;
import org.jground.mail.MailService;
import org.jground.rx.def.RXUser;
import org.jground.rx.ui.IUIMemberLogin;
import org.jground.rx.ui.zk.UIMasterFrame;
import org.jground.rx.web.UIProperties;
import org.jground.util.ArrayUtils;
import org.jground.util.StringUtils;
import org.jground.zk.util.ZKUtils;
import org.jground.zk.zulX.BoxX;
import org.jground.zk.zulX.GridX;
import org.jground.zk.zulX.HboxX;
import org.jground.zk.zulX.LabelX;
import org.jground.zk.zulX.VboxX;
import org.jground.zk.zulX.WindowX;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zul.Button;
import org.zkoss.zul.Html;
import org.zkoss.zul.Image;
import org.zkoss.zul.Messagebox;
import org.zkoss.zul.Textbox;
import org.zkoss.zul.Toolbarbutton;
import org.zkoss.zul.impl.api.InputElement;

public class UIMemberLogin extends WindowX implements IUIMemberLogin<Component, EventListener>, EventListener {

    private static Log logger = LogFactory.getLog(UIMemberLogin.class);
    //
    //
    //
    private UIMasterFrame uiMaster;
    //
    private Button commandBt;
    private List<EventListener> listeners = new ArrayList<EventListener>();
    //
    private VboxX mainPanel;
    //
    private Toolbarbutton loginLink;
    private Toolbarbutton logoutLink;
    private Toolbarbutton lostPasswordLink;
    private Toolbarbutton registerLink;
    private Toolbarbutton doneLink;
    private VboxX selectionPanel;
    //
    private RegisterPanel registerPanel;
    private LoginPanel loginPanel;
    private LogoutPanel logoutPanel;
    private LostPasswordPanel lostPasswordPanel;

    private boolean mailConfirmation;

    public UIMemberLogin() {}

    public void init(Component parent) {
        //
        this.uiMaster = (UIMasterFrame) parent;
        //
        // other inits
        //
        mailConfirmation = "yes".equals(uiMaster.getUiProperty(UIProperties.memberlogin_mailconfirmation));
        //
        //
        //
        this.setStyle("font-size:1.5em");
        this.setBorder("normal");
        //
        createSelectionPanel();
        createActionPanels();
        // 
        // Components
        //
        commandBt = new Button("Member Area");
        //
        Image logo = null;
        VboxX logoBox = null;
        String logoImgSource = uiMaster.getUiProperty(UIProperties.memberlogin_logo);
        if (StringUtils.isNotBlank(logoImgSource)) {
            logo = new Image(logoImgSource);
            logo.setBorder("2px");
            //
            logoBox = new VboxX(logo);
            logoBox.setAlign("center");
            logoBox.setWidth("100%");
        }
        //
        mainPanel = new VboxX();
        mainPanel.setAlign("center");
        mainPanel.setWidth("100%");
        mainPanel.setStyle("margin:10px");
        // 
        // Layout
        //
        if (logoBox != null) {
            add(logoBox);
        }
        add(mainPanel);
        // 
        // Event
        //
        commandBt.addEventListener(Events.ON_CLICK, this);
    }

    private void createSelectionPanel() {
        loginLink = new Toolbarbutton("Member login");
        logoutLink = new Toolbarbutton("Member logout");
        lostPasswordLink = new Toolbarbutton("Send lost password");
        registerLink = new Toolbarbutton("New Member registration");
        doneLink = new Toolbarbutton("Done");
        //
        selectionPanel = new VboxX(loginLink, logoutLink, lostPasswordLink, registerLink, doneLink);
        //
        SelectionListener listener = new SelectionListener();
        loginLink.addEventListener(Events.ON_CLICK, listener);
        logoutLink.addEventListener(Events.ON_CLICK, listener);
        lostPasswordLink.addEventListener(Events.ON_CLICK, listener);
        registerLink.addEventListener(Events.ON_CLICK, listener);
        doneLink.addEventListener(Events.ON_CLICK, listener);
    }

    private void createActionPanels() {
        registerPanel = new RegisterPanel();
        loginPanel = new LoginPanel();
        logoutPanel = new LogoutPanel();
        lostPasswordPanel = new LostPasswordPanel();
    }

    private class ActionPanel extends GridX {

        private HboxX buttonPanel;
        private BoxX messageBox;
        private InputElement[] fields;

        public ActionPanel() {
            super(2);
            messageBox = new BoxX();
            messageBox.setHeight("140px");
            //
            setWidth("420px");
          //  newRow("2", false);
            newRow(2, buttonPanel, false);
            addCells(messageBox);
        }

        protected void init(String[] labels, InputElement[] fields, Button... buttons) {
            this.fields = fields;

            for (int i = 0; i < labels.length; i++) {
                newRow(true);
                addCells(new LabelX(labels[i], "font-weight:bold"), fields[i]);
            }
            buttonPanel = createButtonPanel(buttons);
            newRow(2, buttonPanel, true);
           // addCells(buttonPanel);
        }

        private HboxX createButtonPanel(Button... buttons) {
            HboxX p = new HboxX(buttons);
            p.setAlign("center");
            p.setSpacing("20px");
            p.setStyle("padding:10px");
            return p;
        }

        protected void setMessage(String... msgs) {
            messageBox.set(new Html(messageHtml(msgs)));
        }

        private String messageHtml(String... messages) {
            StringBuilder sb = new StringBuilder();
            for (String m : messages) {
                sb.append("<div style='font-size:1.3em;padding:20px 0px 20px 0px'>");
                sb.append(m);
                sb.append("</div>");
            }
            return sb.toString();
        }

        protected void clearEntryFields() {
            for (InputElement field : fields) {
                field.setText("");
            }
        }
    }

    private class LoginPanel extends ActionPanel implements EventListener {

        private Textbox useridTb;
        private Textbox passwdTb;
        private Button loginBt;
        private Button doneBt;

        public LoginPanel() {
            // COMPONENTS
            useridTb = new Textbox();
            passwdTb = new Textbox();
            passwdTb.setType("password");
            loginBt = new Button("Logout");
            doneBt = new Button("Done");
            // LAYOUT
            super.init(new String[] { "User name", "Password" }, new InputElement[] { useridTb, passwdTb }, loginBt,
                    doneBt);
            // EVENTS
            loginBt.addEventListener(Events.ON_CLICK, this);
            doneBt.addEventListener(Events.ON_CLICK, this);
            //
            setMessage("Please, enter user name and password for login!");
        }

        public void onEvent(Event event) throws Exception {
            // TODO Auto-generated method stub
            String userid = useridTb.getValue();
            String passwd = passwdTb.getValue();
            try {
                if (event.getTarget() == loginBt) {
                    RXUser member = null;
                    if ((member = MemberService.getInstance().checkLoginCredentials(userid, passwd)) == null) {
                        setMessage("Sorry, user name or password is wrong.");
                        return;
                    }
                    MemberService.getInstance().registerPrincipalMethods(member, ZKUtils.getLang(uiMaster),
                            ZKUtils.getHttpSession(uiMaster));
                    fire(LOGIN_OK);
                    return;
                }
                if (event.getTarget() == doneBt) {
                    fire(DONE);
                    return;
                }
            } catch (Exception e) {
                logger.error(e, e);
                setMessage(e.getLocalizedMessage());
            } finally {
                clearEntryFields();
            }
        }

    }

    private class LogoutPanel extends ActionPanel implements EventListener {

        private Button logoutBt;
        private Button doneBt;

        public LogoutPanel() {
            // COMPONENTS
            logoutBt = new Button("Yes, logout");
            doneBt = new Button("No, not logout");
            // LAYOUT
            super.init(new String[] {}, new InputElement[] {}, logoutBt, doneBt);
            // EVENTS
            logoutBt.addEventListener(Events.ON_CLICK, this);
            doneBt.addEventListener(Events.ON_CLICK, this);
            //
            setMessage("Do you really want to logout?");
        }

        public void onEvent(Event event) throws Exception {
            // TODO Auto-generated method stub
            if (event.getTarget() == logoutBt) {
                fire(LOGOUT_OK);
                return;
            }
            if (event.getTarget() == doneBt) {
                fire(DONE);
                return;
            }
        }

    }

    private class RegisterPanel extends ActionPanel implements EventListener {

        private Textbox useridTb;
        private Textbox passwdTb;
        private Textbox passwd2Tb;
        private Button registerBt;
        private Button doneBt;

        public RegisterPanel() {
            // COMPONENTS
            useridTb = new Textbox();
            if (mailConfirmation) {
                useridTb.setConstraint("/.+@.+\\.[a-z]+/: e-mail address only");
            }
            passwdTb = new Textbox();
            passwdTb.setType("password");
            passwd2Tb = new Textbox();
            passwd2Tb.setType("password");
            registerBt = new Button("Register");
            doneBt = new Button("Done");
            // LAYOUT
            super.init(new String[] { "User name", "Password", "Re-type password" }, new InputElement[] { useridTb,
                    passwdTb, passwd2Tb }, registerBt, doneBt);
            // EVENTS
            registerBt.addEventListener(Events.ON_CLICK, this);
            doneBt.addEventListener(Events.ON_CLICK, this);
            //
            setMessage("Please, enter a valid email address as user name and a password with at least 6 letter!");
        }

        public void onEvent(Event event) throws Exception {
            // TODO Auto-generated method stub
            String userid = useridTb.getValue();
            String passwd = passwdTb.getValue();
            String passwd2 = passwd2Tb.getValue();
            try {
                if (event.getTarget() == registerBt) {
                    if (StringUtils.isBlank(userid)) {
                        setMessage("Please, set a user name!");
                        return;
                    }
                    if (passwd == null) {
                        setMessage("Please, set a password");
                        return;
                    }
                    if (StringUtils.isBlank(passwd) || passwd.length() < 5) {
                        setMessage("Please, password with at least 6 characters!");
                        return;
                    }
                    if (!passwd.equals(passwd2)) {
                        setMessage("Retyped password is not the same!");
                        return;
                    }

                    if (MemberService.getInstance().isUseridTaken(userid)) {
                        setMessage("Sorry, the user name " + userid + " is already taken!", "Try another one.");
                        return;
                    }
                    RXUser member = MemberService.getInstance().createNewMember(userid, null, passwd);
                    if (mailConfirmation) {
                        MailService.getInstance()
                                .sendmail(
                                        member.getUserName(),
                                        "Mail Confirmation, please read and confirm",
                                        "Click on the link below please! \n\n"
                                                + MemberService.getInstance().createConfirmationURL(this,
                                                        member.getUserName()));
                        fire(DONE);
                    } else {
                        MemberService.getInstance().registerPrincipalMethods(member, "en",
                                ZKUtils.getHttpSession(uiMaster));
                        fire(REGISTER_OK);
                    }
                    return;
                }
                if (event.getTarget() == doneBt) {
                    fire(DONE);
                    return;
                }
            } catch (Exception e) {
                logger.error(e, e);
                setMessage(e.getLocalizedMessage());
            } finally {
                clearEntryFields();
            }

        }

    }

    private class LostPasswordPanel extends ActionPanel implements EventListener {

        private Textbox useridTb;
        private Button lostPasswordBt;
        private Button doneBt;

        public LostPasswordPanel() {
            // COMPONENTS
            useridTb = new Textbox();
            lostPasswordBt = new Button("Lost password");
            doneBt = new Button("Done");
            // LAYOUT
            super.init(new String[] { "User name" }, new InputElement[] { useridTb }, lostPasswordBt, doneBt);
            // EVENTS
            lostPasswordBt.addEventListener(Events.ON_CLICK, this);
            doneBt.addEventListener(Events.ON_CLICK, this);
            //
            setMessage("Lost your password? Enter your user name and we send it to you!");
        }

        public void onEvent(Event event) throws Exception {
            // TODO Auto-generated method stub
            String userid = useridTb.getValue();
            try {
                if (event.getTarget() == lostPasswordBt) {
                    RXUser[] m = MemberService.getInstance().getMembers(userid);
                    if (ArrayUtils.hasLength(m, 1)) {
                        // send confirmation
                        RXUser user = m[0];
                        MailService.getInstance().sendmail(user.getUserName(), "Requested Lost Password",
                                user.getPassword());
                    }
                    Messagebox.show("The password was sent to you! Press " + doneBt.getLabel() + " for continue");
                    return;
                }
                if (event.getTarget() == doneBt) {
                    fire(DONE);
                    return;
                }
            } catch (Exception e) {
                logger.error(e, e);
                setMessage(e.getLocalizedMessage());
            } finally {
                clearEntryFields();
            }

        }

    }

    public void onEvent(Event event) throws Exception {
        if (event.getTarget() == commandBt) {
            mainPanel.set(selectionPanel);
            fire(OPEN_LOGIN);
        }
    }

    public Component getCommandView() {
        // TODO Auto-generated method stub
        return this.commandBt;
    }

    public Component getView() {
        return this;
    }

    private void fire(String eventName) throws Exception {
        Event event = new Event(eventName, this);
        for (EventListener listener : listeners) {
            listener.onEvent(event);
        }
    }

    public void addEventListener(EventListener listener) {
        listeners.add(listener);
    }

    public void removeEventListener(EventListener listener) {
        listeners.remove(listener);
    }

    private class SelectionListener extends Toolbarbutton implements EventListener {

        public void onEvent(Event event) throws Exception {
            if (event.getTarget() == loginLink) {
                mainPanel.set(loginPanel);
            }
            if (event.getTarget() == logoutLink) {
                mainPanel.set(logoutPanel);
            }
            if (event.getTarget() == registerLink) {
                mainPanel.set(registerPanel);
            }
            if (event.getTarget() == lostPasswordLink) {
                mainPanel.set(lostPasswordPanel);
            }
            if (event.getTarget() == doneLink) {
                fire(DONE);
            }
        }
    }

}
